import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class SimpleThreadPool {
    //任务队列：存放待执行任务的地方，就像工厂的任务传送带
    //BlockingQueue是阻塞队列，当队列空时，取任务的线程会等待
    private final BlockingQueue<Runnable> taskQueue;

    //工人列表：存放所有工作线程的容器
    private final List<Worker> workers;

    //线程池是否关闭的标志，volatile保证多线程可见性
    private volatile boolean isShutdown = false;

    //核小心线程数：就像工厂固定雇佣的工人数量
    private final int corePoolSize;

    /**
     * 构造函数：创建线程池
     *
     * @param corePoolSize 核心线程数量（工人数量）
     * @param queueCapacity 任务队列容量（传送带能放多少个任务）
     */
    public SimpleThreadPool(int corePoolSize, int queueCapacity) {
        this.corePoolSize = corePoolSize;

        //创建一个有界阻塞队列，最多能存放queueCapacity个任务
        this.taskQueue = new ArrayBlockingQueue<>(queueCapacity);

        //创建工人列表
        this.workers = new ArrayList<>();

        //启动所有核心线料雇佣工人并让他们开始工作）
        for (int i = 0; i < corePoolSize; i++) {
            //创建一个工人
            Worker worker = new Worker();
            //把工人加到列表里管理
            workers.add(worker);
            //启动这个工人的线程，让他开始干活
            new Thread(worker).start();
        }
    }


    /***
     * 提交任务到线程池
     * @paramtask要执行的任务
     */
    public void submit(Runnable task) {
        //如果线程池已经关闭，不接受新任务
        if (isShutdown) {
            throw new RuntimeException("线程池已关闭，不能提交新任务");
        }
        try {
            //把任务放到队列里，如果队列满了会阻塞等待
            //就像把零件放到传送带上，如果传送带满了就等一等
            taskQueue.put(task);
        } catch (InterruptedException e) {
            //如果在等待过程中被中断，恢复中断状态
            Thread.currentThread().interrupt();
        }
    }

    /***
     * 关闭线程池
     */
    public void shutdown() {
        //设置关闭标志
        isShutdown = true;
        //通知所有工人停止工作
        workers.forEach(Worker::interrupt);
    }

    /**
     * 工人类：代表一个工作线程
     * 实现Runnable接口，这样就可以放到Thread里运行
     */
    private class Worker implements Runnable  {
        //工人是否被中断的标志
        private volatile boolean interrupted = false;

        @Override
        public void run() {
            //只要没被中断且线程池没关闭，就一直工作
            while (!interrupted && !isShutdown) {
                try {
                    //从任务队列取一个任务，如果队列空了就等待
                    //就像工人从传送带上拿零件，没零件就等着
                    Runnable task = taskQueue.take();

                    //执行任务 (工人开始干活)
                    task.run();
                } catch (InterruptedException e) {
                    //如果在等待任务时被中断，设置中断标志并退出
                    interrupted = true;
                    Thread.currentThread().interrupt();
                }
            }
            //工人工作结束，打印日志便于调试
            System.out.println("工作线程" + Thread.currentThread().getName() + "已停止工作");
        }

        /***
         * 中断工人工作
         */
        public void interrupt() {
            interrupted = true;
        }

    }

}
